Skip to content

feat(tools-list): check deterministic tools/list ordering on the 2026-07-28 wire - #492

Merged
pcarleton merged 4 commits into
modelcontextprotocol:mainfrom
AmirK-S:tools-list-deterministic-order
Sep 6, 2026
Merged

feat(tools-list): check deterministic tools/list ordering on the 2026-07-28 wire#492
pcarleton merged 4 commits into
modelcontextprotocol:mainfrom
AmirK-S:tools-list-deterministic-order

Conversation

@AmirK-S

@AmirK-S AmirK-S commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Discussion: #491.

Requirement

docs/specification/2026-07-28/server/tools.mdx, "Capabilities", lines 71 to 74:

Servers SHOULD return tools in a deterministic order (i.e., the same ordering across requests when the underlying set of tools has not changed). Deterministic ordering enables clients to reliably cache the tool list and improves LLM prompt cache hit rates when tools are included in model context.

https://modelcontextprotocol.io/specification/2026-07-28/server/tools#capabilities

New in 2026-07-28 (absent from 2025-11-25), introduced by modelcontextprotocol/modelcontextprotocol#2516 (not a SEP, so no src/seps/ row). No scenario exercised it before this PR.

What changes

One check added to the existing tools-list scenario (src/scenarios/server/tools.ts), no new scenario, no change to requirements/*.yaml, no src/seps/ row since the sentence does not come from a SEP.

Check Keyword Severity Stimulus Outcome
tools-list-deterministic-order SHOULD WARNING three consecutive tools/list requests, from the 2026-07-28 wire on (source.introducedIn: '2026-07-28', a literal since the revision is published and dated) SUCCESS when the three name sequences are identical; WARNING when the same multiset of names comes back in a different order (first divergent probe and index in errorMessage, the three orders in details.orders); untestable under the #248 policy (Not testable: ..., details.untestable: true, WARNING severity) when the multiset changed between probes, since the spec scopes the SHOULD to an unchanged set; INFO when no probe saw two tools

The helper buildToolsListDeterministicOrderCheck(snapshots) is exported and unit-tested, following buildToolsNameFormatCheck. A failure of a repeated tools/list request is reported as untestable on the new check (via untestableCheck()) instead of turning tools-list itself red. The neighbouring MUST NOT on connection-invariance is deliberately left out, following #332.

Prove it passes and fails

  • Passing: all-scenarios.test.ts already runs tools-list against the everything-server on both wires; on 2026-07-28 the new check is SUCCESS.
  • Failing: examples/servers/typescript/tools-list-rotated-order.ts speaks the sessionless 2026-07-28 wire, advertises the same four tools and rotates the list by one position on every tools/list. The new negative.test.ts case asserts WARNING on tools-list-deterministic-order and SUCCESS on tools-list against it.
node dist/index.js server --url http://localhost:3124/mcp --scenario tools-list --spec-version 2026-07-28
[tools-list                    ] SUCCESS Server lists available tools with valid structure
[tools-name-format             ] SUCCESS Tool names are 1-64 characters and match ^[A-Za-z0-9_./-]+$
[tools-list-deterministic-order] WARNING Consecutive tools/list requests return the same tools in the same order
[wire-schema-valid             ] SUCCESS Every JSON-RPC message the implementation sent is valid per the spec JSON schema for the negotiated spec version
Passed: 3/3, 0 failed, 1 warnings

Runs against real SDKs

typescript-sdk main as of 2026-09-05 (5119ee7fd779), npm start -- sdk typescript-sdk --mode server --scenario tools-list --spec-version 2026-07-28:


Passed: 4/4, 0 failed, 0 warnings

python-sdk main as of 2026-09-05 (7bb486a10fa6), npm start -- sdk python-sdk --mode server --scenario tools-list --spec-version 2026-07-28:

[server] [09/05/26 20:20:35] INFO     Starting MCP Everything Server on     server.py:805
[server] [09/05/26 20:20:36] INFO     Created new          streamable_http_manager.py:325
[server] [09/05/26 20:20:37] INFO     StreamableHTTP       streamable_http_manager.py:166
Passed: 4/4, 0 failed, 0 warnings

Local CI

npm run check and npm run build pass. npm test: 44 files, 536 passed, 0 failed (524 on main plus the 12 added here). The three "Unhandled Rejection" entries vitest reports are present on main before this change.

Notes for review

  • Three probes rather than two, so that a shuffling server cannot pass by repeating one order by chance as easily; happy to change the count.
  • The set-changed case is reported as untestable rather than skipped, per the Standardize how scenarios report setup/execution failures #248 policy, and rather than as a violation, because the spec text itself carves it out. This is where Add SEP-2567 (sessionless Streamable HTTP) conformance coverage #332's sampling concern applied to connection-invariance; here the carve-out is normative, not heuristic. It still surfaces as a WARNING, which CI treats as a failure; SKIPPED or a retry until the set is stable are the alternatives if you prefer.
  • requirements/2026-07-28.yaml lists tools-list as scored and is frozen at scenario granularity, so this check raises the bar for a shipped revision. The requirement is 2026-07-28 text, so I left the file untouched; see tools-list: cover the 2026-07-28 SHOULD on deterministic tools/list ordering #491 for the question, and I will follow whatever you decide.
  • The new check id will appear in untracked in src/seps/traceability.json at the next refresh, for lack of a yaml row.

AI disclosure

Per AI_POLICY.md: this PR, the fixture and the tests were written primarily by Claude Code, pointed at this one SHOULD as AGENTS.md asks, under my direction. Review replies may be AI-assisted as well.

…-07-28 wire

The 2026-07-28 revision adds to server/tools.mdx: "Servers SHOULD return
tools in a deterministic order (i.e., the same ordering across requests
when the underlying set of tools has not changed)." Nothing in the suite
exercised it.

Add a tools-list-deterministic-order check to the existing tools-list
scenario. From the 2026-07-28 wire on, the scenario takes two more
consecutive tools/list snapshots and compares the three name sequences.
Same multiset of names, different order is WARNING (SHOULD). A set that
changed between probes is reported as untestable rather than as a
violation, because the spec scopes the SHOULD to an unchanged set. Fewer
than two tools on every probe is INFO. The check carries
source.introducedIn '2026-07-28', written as a literal since that revision
is published and dated, so runners drop it on earlier wires.

Prove it fails: examples/servers/typescript/tools-list-rotated-order.ts
advertises the same four tools and rotates the list by one position per
call; a negative.test.ts case asserts WARNING while tools-list itself
still passes. Unit tests cover the helper that builds the check.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BjeC3sCvfHRpdEPz2x41B2
@pkg-pr-new

pkg-pr-new Bot commented Sep 6, 2026

Copy link
Copy Markdown

Open in StackBlitz

npx https://pkg.pr.new/@modelcontextprotocol/conformance@492

commit: 8390924

…literal

Check ids and introducedIn revisions are written inline everywhere else in
src/scenarios (tests pin the literal slug on purpose, since SDK baselines
reference it), so drop the two exported constants.

Co-Authored-By: Claude <noreply@anthropic.com>
@pcarleton

Copy link
Copy Markdown
Member

Pushed one small commit inlining the check id and the '2026-07-28' literal (check ids and introducedIn are written inline elsewhere in src/scenarios, and the tests already pin the literal slug). No behaviour change. Thanks for the work on thisone.

pcarleton
pcarleton previously approved these changes Sep 6, 2026

@pcarleton pcarleton left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you!

@pcarleton
pcarleton enabled auto-merge (squash) September 6, 2026 20:01
Resolve conflicts with modelcontextprotocol#380 (tools-name-format): keep both the Tool Names
description line and the deterministic-order line in tools-list, both test
imports, and both negative-test describe blocks.
@pcarleton

Copy link
Copy Markdown
Member

Merged main to resolve the conflicts with #380 (kept both the Tool Names and deterministic-order pieces in tools.ts, tools.test.ts and negative.test.ts); check clean and tools/negative/all-scenarios tests pass. Merging on green.

@pcarleton pcarleton left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ty

@pcarleton
pcarleton merged commit 542381b into modelcontextprotocol:main Sep 6, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants